///<reference path="../typings/tsd.d.ts" />
module AUTO {
    export class AutoTable {
        private static DefaultClassName="autotable";
        private static DefaultEditClassName="autoEdit";
        private static DefaultFreezeClassName="frzTD";
        private static DefaultEventNamespace=".autoTableEvent";
        private static DefaultSelectedClassName="autoselected";
        private static DefaultSaveButtonClassName="autoSave";
        private static DefaultCellEdited='cellEdited';
        private static DefaultRownumID="_rownum";
        
        private _opt: AutoTableOptions={
            data: [],      
            prefix: '',         
            isRownumber: false,   
            header: [],         
            header2: [], 
            headerFields: [],   
            header2Fields: [],
            isFooter: true,      
            
            zeroShowAs: '0',    
            nullShowAs: '',
            isPageable: false,   
            pageNumber: 1,       
            pageSize: 20,       
            pageSizeList: [10, 20, 50, 100],  
            sortFields: [],   
            mergeFields: [],     
            columnsWidths: [],  
            isScrollable: false,   
            freezeFields: [],       
            freezeContainer: window,  
            isSelectable: false,
            selectMulti:true,
            columns: {},           
            tooltipOnRow: null, 
            keydataOnRow: [],   
            editUrl: '',            
            editTable: '',           
            editKeyFields: [],        
            editFields: [],         
            editOn: null,            
            editBeforeUpload: null,   
            filter: null,      
            isAnalyse: false,  
            isSaveable: false, 
            saveURL:"",
            initClass: "table table-striped table-bordered table-condensed table-hover" 
        };
        public me: JQuery;
        private prefix:string="";
        private thead: string="";
        private tbody: string="";
        private tfoot: string="";
        /**下表身还是不要分出来了，保留在同一个table里比较好。 */
        private thead2: string="";
        private tbody2: string="";
        private tcolgroup: string=""; //控制列宽
        private tContainer:JQuery; //控制滚动
        /** 需要显示的数据行 */
        private showData:any[][];  
        /** 需要显示总行数 */
        private rowCount:number;
        /** 总列数  */
        private colunmsCount:number;
        /**是否可编辑 */
        private isEditable:boolean;
        
        constructor(element: Element, options: AutoTableOptions) {
            this.me = $(element);

            this._opt = $.extend(this._opt, options);
            this.prefix = (this._opt.prefix || this.me.attr("id") || ("auto")) + "_";
            this.init();
            this.render();
            this.LastInsert();
            //这些方法只绑定一次即可
            this.bindEvents();
            this.me.data('OriginData', this).trigger('loaded');
        }
         public render(){
            this.renderThead();
            this.renderTfoot();
            this.renderTbody();
            if(this._opt.header2Fields.length>0)
            {
                this.renderThead(2);
                this.renderTbody(2);
            }
        }
         public reloadTbodyTfoot() {
            this.render();
            this.LastInsert();
            if(this._opt.isScrollable)
                this.tContainer.trigger("scroll");
            this.me.trigger("reloaded");
        }
        //最后一步才插入到页面中
        public LastInsert():void{
            this.me.html(this.tcolgroup+this.tbody+this.thead2+this.tbody2+this.thead+this.tfoot);
            this.findDoms();
            //每次表格变动，均重新分析表头
            this.readHeader(); 
            if(this.hidedFields.length>0)
            {
                this.me.trigger("hide",this.hidedFields.join(","));
            }
        }
        public init(): void {
            //1、是不是第一次调此函数。不是则添加样式，是则移除原事件.
            if (this.me.hasClass(AutoTable.DefaultClassName))
               { this.me.off(AutoTable.DefaultEventNamespace);}
            else
               { this.me.addClass(AutoTable.DefaultClassName+" "+this._opt.initClass);
               }
            //2、首先确定表各部分及外部container,以及控制列宽。
            this.tContainer = $(this._opt.freezeContainer);
            if (this._opt.columnsWidths.length) {
                let cols = "";
                _.each(this._opt.columnsWidths, function(w) {
                    cols += `<col width="${w}px" />`;
                });
                this.tcolgroup=cols;
            }
            
            //3、判断data是否是数组,并准备数据
            if (!_.isArray(this._opt.data)) {
                $.auto.alert("错误", "传入的数据不是数组，请检查！")
                return;
            }
            this.showData = _.isFunction(this._opt.filter) ?
                _.filter(this._opt.data, this._opt.filter) :
                this._opt.data;
            this.rowCount=this.showData.length;
            
            //4、如果没有给定headerFields,以及header,则要根据数据生成。
            if (this._opt.data.length){
                if (this._opt.headerFields.length == 0) {
                    for (let key in this._opt.data[0])
                        this._opt.headerFields.push(key);
                }
                if (this._opt.header.length == 0) {
                    let arrHead:AutoTableTHOptions[]=[];
                    for (let key in this._opt.data[0])
                        arrHead.push({title:key,span:[]});
                    this._opt.header.push(arrHead);
                }
            }
            //5、插入序号列
            if(this._opt.isRownumber){
                if(this._opt.headerFields.indexOf(AutoTable.DefaultRownumID)==-1){
                    this._opt.headerFields.unshift(AutoTable.DefaultRownumID);
                    if(this._opt.header2Fields.length)
                        this._opt.header2Fields.unshift(AutoTable.DefaultRownumID);
                }
            }
            this.colunmsCount=this._opt.headerFields.length;
            
            //6、判断编辑功能
            if (this._opt.editFields.length>0&&
                this._opt.editKeyFields.length>0&&
                this._opt.editUrl!=''&&
                this._opt.editTable!='') {
                    this.isEditable=true;
                    this.me.css('table-layout', 'fixed');
                }
                
        }
        //渲染表头。表头以th为基本单元缓存
        private createTh(thOpt: AutoTableTHOptions): string {
            if(thOpt._cache) return thOpt._cache;
            let th ='',th_attr='',th_text='';
            let arr = thOpt.title.split("|");
            //如果有ID
            if (arr[1]) {
                //如果是排序，则标题显示为<a class="autoSort" >title</a> 否则 直接显示
                if (_.includes(this._opt.sortFields, arr[1])) {
                    th_text+=`<a class='autoSort' data-field=${arr[1]}>${arr[0]}</a> `;
                }
                else {
                     th_text+=arr[0];
                }
                th_attr+=`id="${this.prefix + arr[1]}" data-field="${ arr[1]}" `;
            } 
            //没有ID
            else {
                th_text+=arr[0];
            }
            //设置rowspan colspan
            (thOpt.span[0] && thOpt.span[0] != 1) &&(th_attr+=`colspan="${thOpt.span[0]}" `) ;
            (thOpt.span[1] && thOpt.span[1] != 1) &&(th_attr+=`rowspan="${thOpt.span[1]}" `) ;
            (thOpt.span[2])&& (th_attr+=thOpt.span[2]);
            
            th=`<th ${th_attr}>${th_text}</th>`;
            thOpt._cache=th;
            return th;
        }
        /**flag=1 上表头   2：下表头 */
        public renderThead(flag = 1) {
            let scope = this;
            //当前表头参数
            let headeropt = flag == 1 ? this._opt.header : this._opt.header2;
            
            //新版本中，每一行是一个数组。但老版本是{}.老版本转换一下
            if (!_.isArray(headeropt[0])) {
                let header:AutoTableTHOptions[][] = [];
                _.each(headeropt, function(old_row) {
                    let row = [];
                    _.map(old_row, function(v, k) {
                        row.push({ title: k, span: v });
                    })
                    header.push(row);
                });
                if (flag == 1){
                    this._opt.header = header;
                }
                else{
                    this._opt.header2 = header;
                }
                headeropt=header;
            }
            //生成表头内容
            let trs = '';
            _.each(headeropt, function(row) {
                let ths = '';
                _.each(row, function(thOpt) {
                    ths += scope.createTh(thOpt);
                });
                if (flag == 1){
                    trs += `<tr>${ths}</tr>`;
                }else{
                    trs += `<tr class="autoheader2">${ths}</tr>`;
                }
            });
            if (flag == 1)
                scope.thead = `<thead>${trs}</thead>`;
            else
                scope.thead2 = trs;
        }
        //渲染表身，不再缓存行
        private createTR(row: any,rowidx:number,vMerge:any,end :number,flag=1): string {
  
            let scope=this;
            let tr='',tr_attr='',tds='';
            this._opt.tooltipOnRow &&(tr_attr+=`title="${this._opt.tooltipOnRow(row)}" `); 
            
            if(this._opt.keydataOnRow)
            {
                _.each(this._opt.keydataOnRow,function(key){
                    tr_attr+=`data-${key}="${row[key]}" `;
                });
            }
            //循环生成td
            let headerfield=flag==1?this._opt.headerFields:this._opt.header2Fields;
            _.each(headerfield,function(field,idx){
                let td_attr='',td_text='',td_class='';
                
                td_class+=(scope.prefix+field);
                //如果该列需要纵向合并，且该列值不同以上面一个值，则其是一个新单元格.向下搜索长度合并。
                //如果是null，刚不进行合并
                if (_.includes(scope._opt.mergeFields, field)) {
                    if (row[field] != null) {
                        //不等表示是新值，插入td. 否则表示与上一行相同，忽略生成td。
                        if (row[field] == vMerge[field]) {
                            return;//忽略生成td
                        }
                        else {
                            vMerge[field] = row[field];
                            let rowspan = 1;
                            while ((rowidx + rowspan) <= end) {
                                if (scope.showData[rowidx + rowspan][field] == vMerge[field]) rowspan++;
                                else break;
                            }
                            rowspan > 1 &&(td_attr+=`rowspan="${rowspan}" `) ;
                        }
                    }
                    else {
                        vMerge[field] = row[field];
                    }
                }
                //求值
                let curColumn=<AutoTableColumns> scope._opt.columns[field];
                let value=row[field];
                if(curColumn&&_.isFunction(curColumn.formator ))
                {
                    value=curColumn.formator(value,row);
                }else{
                    value=(value==0?scope._opt.zeroShowAs:(value||scope._opt.nullShowAs));
                }
                //冻结
                scope._opt.freezeFields.indexOf(field)>=0&& (td_class+=(" "+AutoTable.DefaultFreezeClassName));
                //列序号
                td_attr+=`data-index="${idx}" `;
                //td上的提示
                if(curColumn&&_.isFunction(curColumn.tooltip ))
                {
                    td_attr+=`title="${curColumn.tooltip(row[field],row)}" `;
                }
                //可编辑
                if (scope.isEditable &&
                    (scope._opt.editOn == null || ((_.isFunction(scope._opt.editOn)) && scope._opt.editOn(field, row))) &&
                    _.includes(scope._opt.editFields, field)
                ) {
                    let kv = {};
                    _.each(scope._opt.editKeyFields, function(f) {
                        kv[f] = row[f];
                    });
                    //只绑定值，当前行的主键值。 url，table是全局使用，不用绑定。
                    td_text += (`<input class="${AutoTable.DefaultEditClassName}" value="${value}" data-field="${field}" data-kv='${JSON.stringify(kv) }' data-old="${value}" />`);
                } else {
                    td_text += value;
                }
                 tds+=`<td class="${td_class}"  ${td_attr}>${td_text}</td>`;
            })
            tr=`<tr ${tr_attr}>${tds}</tr>`;
            row._cache = tr;
            return tr;
        }
        public renderTbody(flag=1){
            let scope=this;
            let trs='';
            let trs2='';//保存下表身的数据行
            let start=0,end=this.showData.length-1;
            if(end<0) return;
            //分页时，设置起始行
            if(this._opt.isPageable){
                start = (this._opt.pageNumber - 1) * this._opt.pageSize;
                end = Math.min(this._opt.pageNumber * this._opt.pageSize-1 , end);
            }
            /** 用于纵向合并判定,第一次访问undefined*/
           let vMerge1={},vMerge2={};
            _.each(this.showData,function(row,ridx){
                if (ridx >= start && ridx <= end) {
                   row[AutoTable.DefaultRownumID]=ridx+1;
                   trs+=scope.createTR(row,ridx,vMerge1,end);
                   if(scope._opt.header2Fields.length>0){
                       trs2+=scope.createTR(row,ridx,vMerge2,end,2);
                   }
                 }
            });
            scope.tbody=`<tbody>${trs}</tbody>`;
            scope.tbody2=trs2;
        }
       
        private pageCount:number;
        public renderTfoot(){
            if(!this._opt.isFooter) return;
            let scope=this;
            let td_attr="",td_text="";
            //临时保存下拉里的option,上页，下页
            let options='',btn1='',btn2='';
            td_attr+=(`colspan="${this.colunmsCount}" `);
            if(this._opt.isPageable){
                //页大小的列表
                this.pageCount= Math.floor((this.rowCount + this._opt.pageSize - 1) / this._opt.pageSize);
                _.each(this._opt.pageSizeList,function(psl){
                     options+=`<option  ${psl==scope._opt.pageSize?'selected="true"':''}>${psl}</option>`; 
                });
                options+='<option value="all">全部</option>';
                td_text+=(`<span>每页<select class="psSelect">${options}</select>条</span>`);
                //当前页码跳转
                options='';
                for(let i=1;i<=this.pageCount;i++){
                    options+=(i==scope._opt.pageNumber)?`<option selected="true">${i}</option>`:`<option>${i}</option>`; 
                }
                td_text+=(`<span>跳转<select class="pnSelect">${options}</select>页</span>`);
                //上页，下页
                btn1=`<button type="button" class="btn btn-default btn-xs" data-flag="prepage" ${this._opt.pageNumber==1?"disabled":""}>上一页</button>`;
                btn2=`<button type="button" class="btn btn-default btn-xs" data-flag="nextpage" ${this._opt.pageNumber==this.pageCount?"disabled":""}>下一页</button>`;
                td_text+= (`<div class="btn-group autoPager">${btn1}${btn2}</div>`) ;
                
            }else{
                td_text +='<button type="button" class="btn btn-default btn-xs" data-flag="paging">启用分页</button>';
            }
            if  (this._opt.isSaveable)
            {
                td_text +=`<button type="button"  class="btn btn-default btn-xs ${AutoTable.DefaultSaveButtonClassName}" >导出</button>`;
            }
            this.tfoot=`<tfoot><td ${td_attr}>${td_text}</td></tfoot>`;
        }

        /** 绑定所有的事件 */
        public frzHead:JQuery;
        public frzTd:JQuery;
        private allEditInput:JQuery;
        private allTheadrows:JQuery;
        private findDoms(){
            //这里要重新绑定
            if  (this.isEditable)
            {
                this.allEditInput=this.me.find("."+AutoTable.DefaultEditClassName);
                this.bindEdit();
            }
            if(this._opt.isScrollable)
            {
                this.frzHead=this.me.find("thead th");
                this.frzTd=this.me.find("."+AutoTable.DefaultFreezeClassName);
            }
            this.allTheadrows=this.me.find("thead>tr");
            if(this._opt.header2Fields.length>0){
                this.allTheadrows=this.allTheadrows.add(this.me.find(".autoheader2"));
            }
        }
       /**解析表头结果，判断每一列穿过哪些th */
        private fieldDict:any; //这个要如何定义一下类型呢，字符串索引XXXXXXXXX
        private readHeader(){
            let scope=this;
             //计算每一列对应哪些表头中的th
            let pos = [[], [], [], [], [], [], [], [], [], []];   //默认表头最大为10行。
            let x =0, y = 0; //pos是二维数组，表示表头的分布着哪些th
            let thInCol = []; //每一列所包含的th
            let tmp1, tmp2;
            this.allTheadrows.each(function (iTR, tr) {
                $(tr).find('th').each(function (iTH, th:HTMLTableHeaderCellElement) {
                    let c = th.colSpan, r = th.rowSpan;
                    for (tmp1 =0; tmp1 < c; tmp1++) { //先处理一列，让这一列增加该td
                        for (tmp2 =0; tmp2 < r; tmp2++) {
                            //如果当前pos已有值，则向后移一格
                            while (typeof pos[y + tmp2][x + tmp1] !== 'undefined') {
                                x++;
                            }
                            pos[y + tmp2][x + tmp1] = th;
                        }
                        thInCol[x + tmp1] = thInCol[x + tmp1] || [];
                        thInCol[x + tmp1].push(th);
                    }
                    //处理下一个td之前，先修改x的值
                    x = x + th.colSpan;
                });
                ////处理下一个tr之前，先修改y的值
                x = 0;
                y++;
            });
            scope.fieldDict = {}; //每个字段对应的列号,及表头列。  
            //上表头中出现的列了。
            $.each(this._opt.headerFields, function (i, field) {
                scope.fieldDict[field]={
                    index: i,
                    ths: thInCol[i]
                };
            });
            //下表头中出现的列了。下表列与上表列相重的部分，务必在同一列上。比如ny,dwmc这些，上下表头要一致！
            $.each(this._opt.header2Fields, function (i, field) {
                scope.fieldDict[field] = {
                    index: i,
                    ths: thInCol[i]
                };
            });
        }
        private hideCol(field:string) {
                //取该字段的索引
                var fdict:AutoTableFieldInfo = this.fieldDict[field];
                var hidTD = this.me.find(`tbody [data-index=${fdict.index }]`);
                fdict.width = hidTD.width();
                _.each(fdict.ths, function (th:HTMLTableHeaderCellElement) {
                    if (th.colSpan > 1) th.colSpan--;
                    else $(th).hide();
                });
                hidTD.hide();
                if (!_.isEmpty(this._opt.columnsWidths)) {  //如果指定了每个列宽，则必须也隐藏相应的col
                      this.me.find(`colgroup col:nth-child(${fdict.index })`).hide();
                }
                this.me.width(this.me.width() - fdict.width);
        }
        private showCol(field:string) {
                //取该字段的索引
                 var fdict:AutoTableFieldInfo = this.fieldDict[field];
                _.each(fdict.ths, function (th:HTMLTableHeaderCellElement) {
                    if ($(th).is(':visible')) th.colSpan++;
                    else $(th).show();
                });
                var hidTD = this.me.find(`tbody [data-index=${fdict.index }]`);
                hidTD.show();
                if (!_.isEmpty(this._opt.columnsWidths)) {  //如果指定了每个列宽，则必须也显示相应的col
                    this.me.find(`colgroup col:nth-child(${fdict.index })`).show();
                }
                this.me.width(this.me.width() + fdict.width);
            }
        /**保存目前的排序信息 */
        private sortInfo:any={};
        private hidedFields:string[]=[];
        /**
         * 绑定点击变色，页面大小，页数变化，排序，锁定表头及列
         */
        public bindEvents() {
            let scope = this;
            //单击变色,单击输入框则不变色
            if (this._opt.isSelectable) {
                this.me.on('click' + AutoTable.DefaultEventNamespace, 'tbody>tr', function(e) {
                    if (!$(e.target).is('input')) {
                        //单选时,如果点击是不是已经选择行，则要清除选择
                        if (!scope._opt.selectMulti && (!$(this).hasClass(AutoTable.DefaultSelectedClassName))) {
                             scope.me.find("."+AutoTable.DefaultSelectedClassName).removeClass(AutoTable.DefaultSelectedClassName);
                        } 
                        $(this).toggleClass(AutoTable.DefaultSelectedClassName);
                    }
                });
            }
            //页面大小变化,页数变化
            this.me.on('change' + AutoTable.DefaultEventNamespace, 'tfoot select', function(e) {
                let $sel = $(this);
                //修改全局的参数
                if ($sel.hasClass("psSelect")) {
                    if ($sel.val() == "all") {
                        scope._opt.isPageable = false;
                    }
                    else {
                        scope._opt.pageSize = parseInt($sel.val());
                        scope._opt.pageNumber = 1;
                    }
                } else if ($sel.hasClass("pnSelect")) {
                    scope._opt.pageNumber = parseInt($sel.val());
                }
                scope.reloadTbodyTfoot();
            });
            //上一页，下一页
            this.me.on('click' + AutoTable.DefaultEventNamespace, 'tfoot button', function(e) {
                let $sel = $(this);
                if ($sel.data("flag") == "prepage") {
                    scope._opt.pageNumber--;
                } else if ($sel.data("flag") == "nextpage") {
                    scope._opt.pageNumber++;
                } else if ($sel.data("flag") == "paging") {
                    scope._opt.pageNumber = 1;
                    scope._opt.isPageable = true;
                }
                scope.reloadTbodyTfoot();
            });
            //排序
            this.me.on('click' + AutoTable.DefaultEventNamespace, 'thead .autoSort,.autoheader2 .autoSort', function(e) {
                let field = $(this).data("field");
                //方向，true正序  false为倒序
                let direction = scope.sortInfo[field];
                direction=_.isUndefined(direction)?true:(!direction);
                //保存起来
                scope.sortInfo[field]=direction;
                scope.showData = _.orderBy(scope.showData, [field],direction?["asc"]:["desc"]);
                scope._opt.pageNumber = 1;
                scope.reloadTbodyTfoot();
            });
            //锁定
            if(scope._opt.isScrollable){
                scope.tContainer.on("scroll"+AutoTable.DefaultEventNamespace,function(){
                    let top=scope.tContainer.scrollTop();
                    let left=scope.tContainer.scrollLeft();
                    scope.frzHead.css({"transform":`translate(0,${top}px)` });
                    scope.frzTd.css({"transform":`translate(${left}px,0)`});
                })
            }
            //隐藏及显示事件
            this.me.on('hide' + AutoTable.DefaultEventNamespace,function(e,fields){
                if (typeof fields == 'undefined') return;  ///表格中带datetimepicker时，也向上冒泡产生show 事件，屏蔽之。
                //传入逗号分隔的字符串，或一个数据。每一项是需要隐藏的列。
                var fArr = fields.split(',');
                _.each(fArr, function (f:string) {
                    if (((_.includes(scope._opt.headerFields,f)) || _.includes(scope._opt.header2Fields,f))  &&  //存在于上下表头列中
                        (!_.includes(scope.hidedFields, f)) && //且未隐藏过
                        (!_.includes(scope._opt.freezeFields, f))) { //且不是冻结列
                        scope.hidedFields.push(f);
                        scope.hideCol(f);
                    }
                }); 
            });
             this.me.on('show' + AutoTable.DefaultEventNamespace,function(e,fields){
                if (typeof fields == 'undefined') return;  ///表格中带datetimepicker时，也向上冒泡产生show 事件，屏蔽之。
                //传入逗号分隔的字符串，或一个数据。每一项是需要隐藏的列。
                var fArr = fields.split(',');
                _.each(fArr, function (f:string) {
                    if (_.includes(scope.hidedFields, f)) { //已经隐藏过
                         var idx_f = _.indexOf(scope.hidedFields, f)
                        scope.hidedFields.splice(idx_f,1);
                        scope.showCol(f);
                    }
                }); 
            });
            //导出
            if(this._opt.isSaveable){
                this.me.on('export' + AutoTable.DefaultEventNamespace,function(){
                     scope.ExportData();
                });
                this.me.on('click' + AutoTable.DefaultEventNamespace, '.'+AutoTable.DefaultSaveButtonClassName, function(){
                     scope.ExportData();
                });
            }
            
        }
        
        public bindEdit(){
            if(this.isEditable)
            {
                let scope=this;
                //提交修改
                this.allEditInput.blur(function(e) {
                    let $input = $(this);
                    let field=$input.data("field"),
                        kv=$input.data("kv"),
                        old=$input.data("old"),
                        v=$.trim( $input.val());
                    if(v==old) return;
                    let upKv=_.clone(kv);
                    //附加上这些值一起上传到后台。这样后台可以用更通用的方法来处理所有的请求。
                    upKv[field] = v;
                    upKv['old_' + field] = old;
                    upKv["_TABLE"] = scope._opt.editTable;
                    upKv["_FIELD"] = field; 
                    //如果有验证，则先验证再提交。
                    //同时引发三个事件，附带上传元素，正修改的单元格及成功标志
                    if (_.isNull(scope._opt.editBeforeUpload) || (_.isFunction(scope._opt.editBeforeUpload) && scope._opt.editBeforeUpload(upKv, field))) {
                        scope.me.trigger('beforeCellEdited', [upKv, $input]);
                        $.ajax(scope._opt.editUrl, {
                            cache: false, type: 'POST',
                            data: upKv, dataType: 'json'}).done(function (ret) {
                                $input.data('old', v);
                                //从showdata中找到当前行，把该field的值修改掉
                                _.find(scope.showData, function (row) {
                                    if (_.isMatch(row, kv)) { row[field] = v;return true; }  
                                    return false;
                                });
                                $input.addClass(AutoTable.DefaultCellEdited);
                                scope.me.trigger('cellEdited', [upKv, $input]);
                                scope.me.trigger('afterCellEdited', [upKv, $input, true]);
                            }).fail( function (XMLHttpRequest, textStatus, errorThrown) {
                                $input.val(old);
                                scope.me.trigger('afterCellEdited', [upKv, $input, false]);
                            });
                        }
                });
                //键盘操作
                this.me.on('keydown' + AutoTable.DefaultEventNamespace, '.'+AutoTable.DefaultEditClassName, function(event) {
                    let newinput=null;
                    if (event.keyCode == 13 || event.keyCode == 39) {  //回车及右
                      let idx=scope.allEditInput.index(this)
                        if (idx < scope.allEditInput.length - 1) newinput = $(scope.allEditInput[idx + 1]);
                    }
                    if (event.keyCode == 37) {  //左
                        newinput=scope.allEditInput.prev();
                        let idx=scope.allEditInput.index(this)
                        if (idx>0) newinput = $(scope.allEditInput[idx -1]);
                    }
                    if (event.keyCode == 38) {  //上
                        let field = $(this).data('field');
                        let list = scope.allEditInput.filter(`[data-field='${field}']`);
                        let idx = list.index(this);
                        if (idx >0 ) newinput = $(list[idx - 1]);
                    }
                    if (event.keyCode == 40) {  //下
                        let field = $(this).data('field');
                        let list = scope.allEditInput.filter(`[data-field='${field}']`);
                        let idx = list.index(this);
                        if (idx < list.length - 1) newinput = $(list[idx + 1]);
                    }
                    if (newinput) {
                        newinput.selectWord();
                        !_.isUndefined( newinput[0].scrollIntoView) || newinput[0].scrollIntoView();
                        return false;
                    }
                    return true;
               }).on("paste" + AutoTable.DefaultEventNamespace, "."+AutoTable.DefaultEditClassName, function (event) {
                  event.stopPropagation();
                  event.preventDefault();
                  let origEvent:ClipboardEvent =<ClipboardEvent> event.originalEvent;
                  let cd = origEvent.clipboardData||window.clipboardData;
                  if (!cd) return;//firefox会走这吗？

                  let content = cd.getData("text");
                  let rows = content.indexOf('\r\n')==-1 ? content.split('\n') : content.split('\r\n');

                  //如果从excel粘贴，则需要弹出最后一个空元素。如果是纯文本，则最后一个非空，不需要弹出。
                  if ($.trim(rows.slice(-1)[0]) == '') {
                      rows.pop();
                  }
                  let xpos = $(this);
                  let ypos = $(this);
                  let field = xpos.data('field');
                  $.each(rows, function (i, r) {
                      xpos = ypos;
                      let cols = r.split('\t');
                      $.each(cols, function (j, c) {
                          xpos.val($.trim(c)).focus().blur();
                          let idx = scope.allEditInput.index(xpos);
                          if (idx < scope.allEditInput.length - 1) { xpos = $(scope.allEditInput[idx + 1]); }
                          else { return; }  //向后无元素了
                      });
                      let list = scope.allEditInput.filter(`[data-field='${field}']`);
                      let index = list.index(ypos);
                      if (index < list.length - 1) ypos = $(list[index + 1]);
                      else return;   //向下无元素了
                  });
              });
            }
        }
        //导出报表结果
        public ExportData() {
            let scope = this;
            var cloneOpt = $.extend(true, {}, this._opt);
            var showData = $.extend(true, {}, this.showData);
            //表头里的标签，比如换行和上标，要在后台进行处理
            var uData: any = _.pick(cloneOpt, "header", "header2",
                "headerFields", "header2Fields");
            var allfield = _.uniq(cloneOpt.header2Fields.concat(cloneOpt.headerFields));
            var rownum = 1;
            _.each(showData, function(row) {
                _.each(allfield, function(key:string) {
                    if (key == "rownum")
                        row[key] = rownum++;
                    else {
                        //显示值的输出。根据columns.formator来格式化数据到uData里
                        if (scope._opt.columns[key] && _.isFunction(scope._opt.columns[key].formator)) {
                            row[key] = scope._opt.columns[key].formator(row[key], row)
                            if (row[key] == null) {
                                row[key] = "";
                            } else {
                                //数据部分要替换掉html标签
                                row[key] = row[key].replace(/<[^>]+>/g, "");
                            }
                        }
                        else
                            row[key] = (row[key] === 0 ? scope._opt.zeroShowAs : (row[key] || scope._opt.nullShowAs));//值为0，显示为0. null，不显示。
                    }
                });
            });
            uData.showData = showData;
            //构造一个下载窗体.
            var $iframe = $('<iframe />');
            var $form = $('<form target="down-file-iframe" method="post" />');
            $form.attr('action', this._opt.saveURL);
            //$form.append("<input  name='d' value='" + JSON.stringify(uData) + "' />");
            var size=84555;
            var content=JSON.stringify(uData);
            var d=1;
            while(content.length>0){
                $form.append(`<input  name='d${d}' value='${content.slice(0,size)}' />`);
                content.slice(size);
                d++;
            }
            
            $iframe.append($form);
            $(document.body).append($iframe);
            (<HTMLFormElement>$form[0]).submit();
            $iframe.remove();
        }
    }
}